// CSE571 - score-cal.cpp
// Authors: Jonathan Wald, Daniel Sarfati, Guangle Fan
// Defines the scoring hands logic.

#include "hand.h"
#include "card.h"
#include "poker.h"
#include <cmath>
#include "score-cal.h"

const unsigned int NUM_CARDS = 5;
const unsigned int CARD_ARRAY_SIZE = 6;
const unsigned int NUM_RANK = 13;
enum HAND_RANK_RATIO {PAIR_R = 1, TWOPAIR_R, TOAK_R, STRAIGHT_R, FLUSH_R, FULLHOUSE_R, FOAK_R, STAIGHTFLUSH_R};
enum SCORE_POWER_BIT {FIRST_B = 1, SECOND_B, THIRD_B, FOURTH_B};
const int SIG_DIF = -1;
const int PAIR_DIF = -2;
const int TOAK_DIF = -3;
const int FOAK_DIF = -4;
const int FOUR_DIF = 4;
 const int POWER_ONE = 13, POWER_TWO = 169, POWER_THREE = 2197, POWER_FOUR = 28561, POWER_FIVE = 371293;


int scoreArray[CARD_ARRAY_SIZE];

int  getHandScore (const Hand &hand) {
  int score = 0;
  vector<Card> vec = hand.getHand();
  std::sort(vec.begin(), vec.end());
  int HandRank = getHandRank (hand);

  if (HandRank == NO_RANK) {
    for (unsigned int i = 0; i < NUM_CARDS; ++i) {
      score += vec[i].c_rank * std::pow (NUM_RANK, i);
    }
  }
  else if (HandRank == PAIR) {
    score = PAIR_R * POWER_FIVE + scoreArray[FOURTH_B] * POWER_FOUR + scoreArray[THIRD_B] * POWER_THREE + scoreArray[SECOND_B] * POWER_TWO + scoreArray[FIRST_B] * POWER_ONE;
  }
  else if (HandRank == TWO_PAIR) {
    score = TWOPAIR_R * POWER_FIVE + scoreArray[FOURTH_B] * POWER_FOUR + scoreArray[THIRD_B] * POWER_THREE + scoreArray[SECOND_B] * POWER_TWO;
  }
  else if (HandRank == THREE_OF_A_KIND) {
    score = TOAK_R * POWER_FIVE + scoreArray[FOURTH_B] * POWER_FOUR + scoreArray[THIRD_B] * POWER_THREE + scoreArray[SECOND_B] * POWER_TWO;
  }
  else if (HandRank == STRAIGHT) {
    int high = (int) vec.back().c_rank;
    score = STRAIGHT_R * POWER_FIVE + high * POWER_FOUR;
  }
  else if (HandRank == FLUSH) {
    score += FLUSH_R * POWER_FIVE;
    for (unsigned int j = 0; j < NUM_CARDS; ++j) {
      score += vec[j].c_rank * std::pow (NUM_RANK, j);
    }
  }
  else if (HandRank == FULL_HOUSE) {
    score = FULLHOUSE_R * POWER_FIVE + scoreArray[FOURTH_B] * POWER_FOUR + scoreArray[THIRD_B] * POWER_THREE;
  }
  else if (HandRank == FOUR_OF_A_KIND) {
    score = FOAK_R * POWER_FIVE + scoreArray[FOURTH_B] * POWER_FOUR + scoreArray[THIRD_B] * POWER_THREE;
  }
  else if (HandRank == STRAIGHT_FLUSH) {
    int highRank = (int) (vec.back().c_rank);
    score = STAIGHTFLUSH_R * POWER_FIVE + highRank * POWER_FOUR;
  }
  return score;
}

bool isFlush(Card c1, Card c2, Card c3, Card c4, Card c5){
  if(c1.c_suit == c2.c_suit && c2.c_suit == c3.c_suit && c3.c_suit == c4.c_suit && c4.c_suit == c5.c_suit)
    return true;
  return false;
}
bool isStraight(Card c1, Card c2, Card c3, Card c4, Card c5){
  for(int i = 0; i < 8; ++i){
    if(c1.c_rank == i && c2.c_rank == i+1 && c3.c_rank == i+2 && c4.c_rank == i+3 && c5.c_rank == i+4)
      return true;
  
    if(c1.c_rank == Card::ace && c2.c_rank == Card::two && c3.c_rank == Card::three && c4.c_rank == Card::four && c5.c_rank == Card::five)
      return true;
  }
  return false;
}

bool isStraightFlush(Card c1, Card c2, Card c3, Card c4, Card c5){
  if(isFlush(c1,c2,c3,c4,c5) && isStraight(c1,c2,c3,c4,c5))
    return true;
  return false;
}
bool isFourOfAKind(Card c1, Card c2, Card c3, Card c4, Card c5){
  bool result = false;
  int ranks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  ranks[c1.c_rank]--;
  ranks[c2.c_rank]--;
  ranks[c3.c_rank]--;
  ranks[c4.c_rank]--;
  ranks[c5.c_rank]--;
  for(unsigned int i = 0; i < NUM_RANK; ++i){
    if(ranks[i] == FOAK_DIF){
      scoreArray[FOURTH_B] = i;
      result = true;
    }
    if(ranks[i] == SIG_DIF){
      scoreArray[THIRD_B] = i;
    }
  }
  return result;
}
bool isFullHouse(Card c1, Card c2, Card c3, Card c4, Card c5){
  int ranks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  ranks[c1.c_rank]--;
  ranks[c2.c_rank]--;
  ranks[c3.c_rank]--;
  ranks[c4.c_rank]--;
  ranks[c5.c_rank]--;
  bool three = false, two = false;
  for(unsigned int i = 0; i < NUM_RANK; ++i){
    if(ranks[i] == TOAK_DIF){
      scoreArray[FOURTH_B] = i;	  
      three = true;
    }
    if(ranks[i] == PAIR_DIF){
      scoreArray[THIRD_B] = i;
      two = true;
    }
  }
  return three && two;
}
bool isThreeOfAKind(Card c1, Card c2, Card c3, Card c4, Card c5){
  bool result = false;
  int higher = -1;
  int lower = -1;
  int ranks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  ranks[c1.c_rank]--;
  ranks[c2.c_rank]--;
  ranks[c3.c_rank]--;
  ranks[c4.c_rank]--;
  ranks[c5.c_rank]--;
  for(unsigned int i = 0; i < NUM_RANK; ++i){
    if(ranks[i] == TOAK_DIF) {
      scoreArray[FOURTH_B] = i;
      result = true;
    }
    else if(ranks[i] == SIG_DIF && lower == -1)
      lower = i;
    else if(ranks[i] == SIG_DIF) {
      higher = i;
    }
  }
  scoreArray[THIRD_B] = higher;
  scoreArray[SECOND_B] = lower;
  return result;
}
bool isTwoPair(Card c1, Card c2, Card c3, Card c4, Card c5){
  int ranks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };  
  ranks[c1.c_rank]--;
  ranks[c2.c_rank]--;
  ranks[c3.c_rank]--;
  ranks[c4.c_rank]--;
  ranks[c5.c_rank]--;
  bool firstTwo = false, secondTwo = false;
  for(unsigned int i = 0; i < NUM_RANK; ++i){
    if(ranks[i] == PAIR_DIF && !firstTwo){
      scoreArray[THIRD_B] = i;
      firstTwo = true;
    }
    else if(ranks[i] == PAIR_DIF){
      scoreArray[FOURTH_B] = i;
      secondTwo = true;
    }
    else if(ranks[i] == SIG_DIF){
      scoreArray[SECOND_B] = i;
    }
  }
  return firstTwo && secondTwo;
}

bool isPair(Card c1, Card c2, Card c3, Card c4, Card c5){
  int ranks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  ranks[c1.c_rank]--;
  ranks[c2.c_rank]--;
  ranks[c3.c_rank]--;
  ranks[c4.c_rank]--;
  ranks[c5.c_rank]--;
  int different = 0;
  int t = 1;
  for(unsigned int i = 0; i < NUM_RANK; ++i){
    if(ranks[i] == SIG_DIF){
      scoreArray[t] = i;
      ++t;
      ++different;
    }
    else if(ranks[i] == PAIR_DIF){
      scoreArray[FOURTH_B] = i;
    }
  }
  return different <= FOUR_DIF;
}
